// SPDX-License-Identifier: GPL-2.0 or GPL-3.0
// Copyright © 2018-2019 Ariadne Devos
/* s2 -- accept HTTP connections */

#include "worker.h"
#include "fd.h"

#include <sHT/accept.h>
#include <sHT/bugs.h>
#include <sHT/compiler.h>
#include <sHT/nospec.h>
#include <sHT/resource.h>
#include <sHT/stream.h>
#include <sHT/test.h>

#include <string.h>

/* TODO: configuration, errno handling in task/accept.c, task/sockrw.c */
static const char test_message[] =
  "HTTP/1.1 200 OK\r\n"
  "Server: sHTTPd\r\n"
  "Connection: Close\r\n"
  "Content-Type: text/plain\r\n"
  "Content-Language: en\r\n"
  "\r\n"
  "Hello!";

struct sHT_task_stream *
sHT_accept_subtask(struct sHT_worker *worker, struct sHT_task_accept *task)
{
	/* TODO: allow different settings for different TCP ports */
	return sHT_alloc(worker->free_streams);
}

void
sHT_accept_abort(struct sHT_worker *worker, struct sHT_task_accept *task, struct sHT_task_stream *subtask)
{
	sHT_free(worker->free_streams, subtask);
}

void
sHT_accept_logic(struct sHT_worker *worker, struct sHT_task_accept *task, struct sHT_task_stream *subtask)
{
	_Bool oops = sHT_init_stream(worker->papers, &subtask->stream);
	if (sHT_nonzero_p(oops)) {
		/* XXX Spectre: what if this branch is ignored?
		   Then a NULL paper might be written to,
		   might be problematic.  */
		sHT_close(subtask->stream.fd);
		sHT_free(worker->free_streams, subtask);
		return;
	}
	/* TODO: consider patching the kernel to allow 'reservation' of
	   epoll events. TODO: reconsider this previous TODO. */
	oops = sHT_install_edge_trigger(worker->watches, subtask->stream.fd, &subtask->task);
	if (sHT_nonzero_p(oops)) {
		/* Spectre: a speculatively missing watch isn't problematic.
		   For a teeny while,
		   the task won't run although it should be. */
		sHT_free_stream(worker->papers, &subtask->stream);
		sHT_close(subtask->stream.fd);
		sHT_free(worker->free_streams, subtask);
		return;
	}
	sHT_assert(subtask->stream.to_write.offset == 0);
	sHT_assert(subtask->stream.to_write.length == 0);
	sHT_assert(sizeof(test_message) <= sHT_PAPER_SIZE);
	memcpy(subtask->stream.to_write.first, test_message, sizeof(test_message));
	sHT_init_task(&subtask->task);
	subtask->task.epollflags |= EPOLLIN | EPOLLOUT;
	subtask->stream.to_write.length = sizeof(test_message);
}
